﻿using System;
using System.IO;
using System.Text;
using System.Xml;
using CommandLineParser.Arguments;
using uTILLIty.Rave.Commandline.Properties;
using uTILLIty.Rave.Contract.Configuration;
using uTILLIty.Rave.Contract.StorageAdapter;
using uTILLIty.Rave.Core.Configuration;
using uTILLIty.Rave.Core.Manager;

namespace uTILLIty.Rave.Commandline
{
	/// <summary>
	/// Reads and prints the ACLs of a given path using a given <see cref="TargetSystem"/>
	/// </summary>
	public class ReadAclsCommand : BaseCommand
	{
		/// <summary>
		/// The directory/path to extract ACL information from (interpreted by the <see cref="TargetSystem"/>)
		/// </summary>
    [ValueArgument(typeof(string), 'd', "dir", Optional = false, 
			Description = "The directory/path to extract ACL information from", Example = @"-d c:\Temp\Project-Template")]
		public string Directory;

		/// <summary>
		/// Optional. The target-system (see public API an well-known StorageAdapters). Default=NtfsFileSystem
		/// </summary>
		/// <see cref="IStorageAdapter"/>
		[ValueArgument(typeof(string), 't', "target", Optional = true, DefaultValue = "NtfsFileSystem",
			Description = "Optional. The target-system (see public API an well-known StorageAdapters). Default=NtfsFileSystem", Example = @"-t NtfsFileSystem")]
		public string TargetSystem;

		/// <summary>
		/// Optional. The filename to output XML to
		/// </summary>
		[FileArgument('x', "xml", Optional = true, FileMustExist = false, Description = " The filename to output XML to", Example = "-x template.xml")]
		public FileInfo OutputXmlFilename;

		/// <summary>
		/// Wether to also parse sub-folders
		/// </summary>
		[ValueArgument(typeof(bool), 'r', "recursive", Optional = true, Description = "Wether to also parse sub-folders")]
		public bool Recursive;

		private readonly ConfigurationManager _configurationManager;

		/// <summary>
		/// Creates a new instance of the <see cref="ReadAclsCommand"/>
		/// </summary>
		public ReadAclsCommand(ConfigurationManager configurationManager)
		{
			_configurationManager = configurationManager;
		}

		/// <summary>
		/// Executes the command
		/// </summary>
		protected override void OnExecute()
		{
			var config = _configurationManager.BuildFromDirectory(Directory, TargetSystem, Recursive, VisitDirectory, HandleVisitingError);

			if (OutputXmlFilename != null)
				ExportConfiguration(config);
		}

		private void VisitDirectory(ConfigurationExtensions.VisitingContext context)
		{
			Console.WriteLine(Resources.RetrievingAcls, context.DirectoryContext);

			if (OutputXmlFilename != null)
				return;

			foreach (var entry in context.DirectoryContext.Directory.SecurityEntries)
			{
				Console.WriteLine(Resources.MemberPrintout, entry.MemberID);
				if (!string.IsNullOrWhiteSpace(entry.Rights))
					Console.WriteLine(Resources.RightsPrintout, entry.AccessControlType, entry.Rights);
				Console.WriteLine(Resources.PropagationFlagsPrintout, entry.PropagationFlags);
				Console.WriteLine(Resources.InheritanceFlagsPrintout, entry.InheritanceFlags);
				Console.WriteLine();
			}
		}

		private void HandleVisitingError(ConfigurationExtensions.VisitingError context)
		{
			Console.WriteLine(context.Exception.Message);
			context.Rethrow = false;
			context.VisitChildren = false;
		}

		private void ExportConfiguration(Configuration config)
		{
			var xml = config.ToXml(Encoding.UTF8, Formatting.Indented);
			File.WriteAllText(OutputXmlFilename.FullName, xml, Encoding.UTF8);
			Console.WriteLine(Resources.ConfigXmlWrittenToFile, OutputXmlFilename.FullName);
		}
	}
}